import { NEChartsRelate } from "../declare/base";
import {EChartOption} from "echarts";
import {SeriesValDataList} from "./SeriesValDataList";
import {getAxisRange} from "../func/axis";

export namespace AxisInfo {
    export type TAxis =  EChartOption.YAxis | EChartOption.XAxis;
    export interface IStackMapItem {
        min: number;
        max: number;
    }
}

export class AxisInfo {
    private min: number = NaN;
    private max: number = NaN;
    private stackMapList = new Map<string, AxisInfo.IStackMapItem>();
    private isUpdateRange: boolean = false;
    public readonly axis: AxisInfo.TAxis;
    public isReferZero: boolean = true;
    public scaleFactor: number = 9 / 10;
    public get isHavingOriginRange(): boolean {
        return !isNaN(this.axis.min as number) || !isNaN(this.axis.max as number);
    }
    constructor(yAxis: AxisInfo.TAxis) {
        this.axis = yAxis;
    }
    public isValueAxis(): boolean {
        return this.axis.type === "value";
    }
    public isShow(): boolean {
        return !!this.axis.show;
    }

    public getStackMapItemOf(stack: string): AxisInfo.IStackMapItem {
        if (!this.stackMapList.has(stack)) {
            this.stackMapList.set(stack, {
                min: NaN,
                max: NaN,
            });
        }
        return this.stackMapList.get(stack) as AxisInfo.IStackMapItem;
    }

    public updateStackMapItemMin(stack: string, dataMin: number): this {
        const stackMapItem = this.getStackMapItemOf(stack);
        if (isNaN(stackMapItem.min)) {
            stackMapItem.min = dataMin;
        } else if (!isNaN(dataMin)) {
            if (dataMin >= 0 && stackMapItem.min > dataMin) {
                stackMapItem.min = dataMin;
            } else if (dataMin < 0) {
                if (stackMapItem.min > 0) {
                    stackMapItem.min = dataMin;
                } else {
                    stackMapItem.min += dataMin;
                }
            }
        }
        this.setMin(stackMapItem.min);
        return this;
    }

    public updateStackMapItemMax(stack: string, dataMax: number): this {
        const stackMapItem = this.getStackMapItemOf(stack);
        if (isNaN(stackMapItem.max)) {
            stackMapItem.max = dataMax;
        } else if (!isNaN(dataMax)) {
            if (dataMax >= 0 && stackMapItem.max >= 0) {
                stackMapItem.max += dataMax;
            } else if (dataMax * stackMapItem.max <= 0) {
                stackMapItem.max = Math.max(dataMax, stackMapItem.max);
            } else {
                stackMapItem.max = 0;
            }
        }
        this.setMax(stackMapItem.max);
        return this;
    }

    public setStackMapItemRange(stack: string, data: SeriesValDataList.TDataList) {
        const dataList = new SeriesValDataList(data);
        this.updateStackMapItemMax(stack, dataList.getMax()).updateStackMapItemMin(stack, dataList.getMin());
    }

    public setRangeFromDataList(data: SeriesValDataList.TDataList, stack?: string): this {
        if (stack) {
            this.setStackMapItemRange(stack, data);
        } else {
            const dataList = new SeriesValDataList(data);
            this.setMin(dataList.getMin()).setMax(dataList.getMax());
        }
        return this;
    }

    public setMin(min: number): this {
        this.isUpdateRange = true;
        if (isNaN(this.min) || min < this.min) {
            this.min = min;
        }
        return this;
    }

    public setMax(max: number): this {
        this.isUpdateRange = true;
        if (isNaN(this.max) || max > this.max) {
            this.max = max;
        }
        return this;
    }

    public getBaseRange(): NEChartsRelate.IRange {
        return {
            min: this.min,
            max: this.max,
        };
    }

    public hasUpdateRange(): boolean {
        return this.isUpdateRange;
    }

    public resetRangeOfAxis(splitNumber: number = 5, axis?: AxisInfo.TAxis): this {
        const modifyAxis = axis || this.axis;
        const baseRange = this.getBaseRange();
        const range = getAxisRange({
            min: baseRange.min,
            max: baseRange.max,
            splitNumber,
            scaleFactor: this.scaleFactor,
            isReferZero: this.isReferZero,
        });
        modifyAxis.min = range.min;
        modifyAxis.max = range.max;
        modifyAxis.interval = range.interval;
        modifyAxis.splitNumber = range.splitNumber;
        return this;
    }
}
